#-*- coding:utf-8 -*-
'''
    2017-12-10 morning library second floor
    Sun Jonson
    
    python 标准库文档
        functional programming modules
'''
import itertools
def FPM():
    '''两个表的并行操作
    '''
    vec1=[1,2,3,4,5,6,7]
    vec2=[7,6,5,4,3,2,1]
    two_vec=list( map(lambda a,b:a*b,vec1,vec2) )
    print(two_vec)

    #内存占用96% cpu25%   为什么内存占用达不到100%？？？
    #list( itertools.count(10))
    cyc=(2,454,67,153)
    cy1=itertools.cycle(cyc) 
    print(next(cy1),next(cy1),next(cy1),next(cy1),next(cy1)  )
    print('指定重复次数：')
    print(list( itertools.repeat(cyc,10) ) )
    
    print('前一项和后一项的加 和:')
    print(list(itertools.accumulate(vec1) ) )
    print('连接多个可迭代内容:')
    print(list(itertools.chain(vec2,vec1,vec2,vec1) ) )
    print('链式迭代：')
    print(list( itertools.chain.from_iterable(['absdk','aksjhiuwen']) )  )
    print('返回按列表2校验 为真的元素')
    print(list(itertools.compress('abcdefg',[1,2,0,0,1,0,True]) ) )
    print('到不满足条件时停止：')
    print(list(itertools.takewhile(lambda x :x < 4,[1,2,3,4,5,3,2,1]) ) )
    print('到不满足条件时开始输出：')
    print(list(itertools.dropwhile(lambda x:x>4,vec2) ) )
    print('过滤掉不满足条件项：')
    print(list(itertools.filterfalse(lambda x : x%3,list(range(30) )) ) )
    print('切片：')
    print(list(itertools.islice(vec1,0,4,1) ) ) 
    print('元组映射：')
    print(list(itertools.starmap(pow,[(2,3),(2,4),(2,5)]) ) )
    print('最长合并：')
    print(list(itertools.zip_longest('asdfghjkl',(1,2,3,4,5),fillvalue='_') ) )
    #笛卡尔积： 
    print(list(itertools.product('asdfgh',vec1) ) )
    print('cyc 的排列:')
    print(list(itertools.permutations(cyc,2) ) )
    print('输出组合:')
    print(list(itertools.combinations(cyc,2) ) )
    print('包含自身(可重复)的组合：')
    print(list(itertools.combinations_with_replacement(cyc,2) ) )
    print('多元笛卡尔积:')
    print(list(itertools.product('abcd',repeat=2) ) )
    print('多元排列：')
    print(list(itertools.permutations('abcd',3) ) )
    print('多元组合：')
    print(list(itertools.combinations('abcd',3) ) )
    print('多元可重复组合：')
    print(list(itertools.combinations_with_replacement('abcd',3) ) )
    print('分组：')
    print([(k,list(g) ) for k,g in itertools.groupby('aaaccdwwssxxxggkkttll')] )
    print('获得多个迭代器：')
    iter1,iter2=itertools.tee(vec1,2)  #获得两个vec1的迭代器
    print(next(iter1),next(iter2))
#FPM()
'''
函数式编程：
    17-10/4
    形式：预算控制（运算式，数据）
    reduce() 需要导入
'''
from functools import reduce
import random
def map_reduce():
    ''' 
    基本操作   函数式编程FP-并,串运算
    '''
    #   function
    
    add=lambda x:x+2;
    add1=lambda x,y:x+y
    
    #   data
    data=[1,2,3.4,5,9]
    data1=range(1,500,5)
    
    #   map
    result=list(map(add,data))
    print('map:\n',result)
    #map 操纵两个list
    result=map(add1,[1,2,3,4,5],[6,7,8,9,10])
    #print(list(result))
    
    #   zip
    result=zip([1,2,3,4,5],[6,7,8,9,10])
    print('zip2:\n',list(result))
    result=zip([1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15])
    print('zip3:\n',list(result))
    
    #   reduce
    result1=reduce(add1,data1)
    print('reduce;\n',result1)
    
    #   filter
    data2=filter(lambda x:x<50,data1)
    print('filter:\n',list(data2))
    
    #控制语句替换
    def func(x):
        '''一般情况 '''
        if x==1:
            print('1')
        elif x==2:
            print('2')
        else:
            print('3')
    def pr(s):
        print(str(s))
        return True
    print_num=lambda x:(x==1 and pr(1)) or \
                        (x==2 and pr(2)) or \
                        (pr(3))
    print('print_num: ')
    print_num(1)
    print_num(2)
    print('func : ')
    func(1)
    func(2)
#---------------------------------------------

def use_fp_1():
    '''初次应用
        map里的函数 操作数一般为1个
        reduce里的函数 操作数为2个
        出错一般在报错位置的上一行。
    '''
    #算式
    rr=random.randrange  #少用.操作符加快运行速度。
    mode=lambda one:one%rr(3,33)  #random.randrange(3,13)
    multi=lambda one,two:(one+two)
    #数据 
    data=range(100,200)
    #操作 
    result=list(map(mode,data))#list化
    #print('result:',result)
    result1=reduce(multi,list(result))
    
    result2=reduce(multi,list(map(mode,data)))
    print('reduce_map1:\n',result1)
    print('reduce_map2:\n',result2)
    
    result3=list(map(mode,range(3,reduce(multi,data)%100)))
    print('map_reduce:\n',result3)
    
#----------------------------------

def jiecheng(n):
    '''阶乘'''
    if n is 1:
        return 1
    else:
        return n*jiecheng(n-1)
def funA():
    x=0
    def funB():
        nonlocal x
        x += 1
        #print('x:',x)
        return x
    return funB
def use_fp_2():
     ''' 函数式编程的特点；常量、闭包'''
     #常量性
     result=range(1,10)
     result=map(jiecheng,result)
     print('jiecheng:',list(result))
     g=lambda n:reduce(lambda x,y:x*y,range(1,n))
     print('g(8):',g(20))
     #闭包性:(提供可变的输入？？)
     #闭包是绑定了外部作用域的变量（但不是全局变量）的函数。
     #大部分情况下外部作用域指的是外部函数。
     print('闭包性验证：')
     a=funA()
     print(a())
     print(a())
     print(a())
     
     n=1
     def inner():
        print(n)
     inner()
     n='x'
     inner()
    
     print("闭包：")
     def addx(x):
        return lambda y:x+y
     add8=addx(8)
     add9=addx(9)
     print(add8(100))
     print(add9(100))
#---------------------------------------

def compare(num1):
    return 50-num1
def call_compare():
    lst=list(range(20))
    result=sorted(lst,key=compare)
    print(result)
    
    #两个参数怎么办？？
    #lat=lst.sort(key=lambda o1,o2: o1.compare(o2) )
    #print(lat)
    
#------------------
import funcy
def funcy_use():
    ''' 练习使用 funcy 库'''
    up=funcy.walk(str.upper,{'a','b','z','x','c','v','b','n','m'})
    print('转化为大写：',up)
    print('加倍：',funcy.walk_keys(lambda x:x+x,{'a':1,'b':2}))
    
#------------------
import functools as ftl
def used_func():
	#functools模块中的工具的使用
	#ftl.cmp_to_key(function object)  #比较函数转换为key函数
	#最近最少使用缓冲 maxsize为2的指数
	#作为包装器 @lru_cache 在函数之前
	#ftl.lru_cache(maxsize=128)  
	#@ftl.total_ordering  ??
	#partial()  ??
	#partialmethod()  ??
	#ftl.reduce()  #上面讲过
	#ftl.singledispatch()  register()
	#ftl.update_wrapper()  ??
	#ftl.wraps()  ??
	
#------------------

#------------------

#------------------

def main():
    '''运行控制函数 '''
    #map_reduce()
    #use_fp_1()
    #use_fp_2()
    #call_compare()
    #funcy_use()
    
    #input("\n---  ---  --\nenter over:")
if __name__=='__main__':
    main()
    #input('结束：')
'''
1、基本操作：
    lambda 、map 、functools.reduce、
    filter、尾递归（for）、条件（and，or替换if else）
2、组合操作。



任何情况下，使用相同的参数调用函数始终能产生同样的结果

递归是另一种取代循环的方法。递归其实是函数式编程很常见的形式，经常可以在一些算法中见到。但之所以放到最后，是因为实际上我们一般很少用到递归。如果一个递归无法被编译器或解释器优化，很容易就会产生栈溢出；另一方面复杂的递归往往让人感觉迷惑，不如循环清晰，所以众多最佳实践均指出使用循环而非递归。

迭代器的另一个优点就是它不要求你事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代至某个元素时才计算该元素，而在这之前或之后，元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合，比如几个G的文件，或是斐波那契数列等等。这个特点被称为延迟计算或惰性求值(Lazy evaluation)。

>>> lst = range(2)
>>> it = iter(lst)
>>> it
>>> it.next()
>>> next(it) 

迭代器更大的功劳是提供了一个统一的访问集合的接口。只要是实现了__iter__()方法的对象，就可以使用迭代器进行访问。
Python正是根据是否检查到这个异常来决定是否停止迭代的。 
首先Python将对关键字in后的对象调用iter函数获取迭代器，然后调用迭代器的next方法获取元素，直到抛出StopIteration异常。

函数式语言不仅在 JVM 上刚刚崭露头脚（其中两个最有趣的新语言是 Scala 和 Clojure），在 .NET 平台上也是才开始得到应用，在 .NET 平台上，F# 是头等公民。

高阶函数可以将其他函数作为参数或者返回结果
函数可以嵌套定义，即在一个函数内部可以定义另一个函数

自由变量是指除局部变量以外的变量。


monad:   https://bartoszmilewski.com/
'''
def fun_use():
    print('/*  - - - -函数使用 --  -- - - -*/')
    zu=[1,-2,20,4,-5,6,7]
    print('数组sum结果：',sum(zu))
    print('sorted排序返回新数组：',sorted(zu))

    zu=[0,9,6,8,5,4]
    zu.sort()#在原有位置排序，效率更高，无返回值
    print('sort原位置排序：',zu)

    cck=sorted("This is a test string from Andrew".split(), key=str.lower)
    print('字符串排序：',cck)

    it=iter(zu)
    print('迭代器的两种使用方式：',it.__next__(),next(it))
    a,b,c,d=it
    print('a,b,c=iterator:继续向下（必须完全解包）：',a,b,c,d)

    it=iter(zu)
    #print('输出迭代器：',list(it))
    t=tuple(it)
    print('tuple用法：',t)
def double_iter_use():    
    seq1='abcd'
    seq=[2,7,9,3,4,5,6,5,7]
    seq2=[5,4,3,2,8,5,4,1,0]
    seq3=[(x,y) for x in seq1 for y in seq]
    print('双迭代器演示 笛卡尔积：',seq3)
    seq4=list(map(lambda it1,it2:it1*it2,seq,seq2))
    print('两个迭代器并行遍历两个数组',seq4)

def generator(n):
    ''' 生成器使用'''
    for i in range(n):
        yield i   #返回生成器对象，支持迭代协议
def yield_use(a):
    a+=3
    yield a
    a*=2
    yield a
    yield a/3
    
def gen_use():        
    gen=generator(20)
    print('遍历生成器方式',next(gen),next(gen),next(gen),next(gen))
    
    for i in yield_use(3):
        print(str(i)+',')
    #Generator Expression   
    G = (x for x in range(4))
    for si in G:
        print(si,end=' ')
    xl = [1,3,5]
    yl = [9,12,13]
    L  = [ x**2 for (x,y) in zip(xl,yl) if y > 10]  
    print(L)
#gen_use()  
  
import random
def rand_use():
    rand_list = random.sample(range(1010), 8)
    print('随机生成的列表：',rand_list)
    
def little_fun_use():
    print('any  的使用：',any([0,0,0,3]),any([True,False,0,0]))
    print('all 的使用：',all([1,2,9,3]))
    print('zip() 的使用：',list(zip([2,3,5,7],[3,6,5,3])) )

import itertools
def less_than_10(x):
    return x<10
def itr_use(): 
    print('/*  - - 迭代器- - --  -- - - -*/')
    print(itertools.count())    
    print(list(itertools.takewhile(less_than_10, itertools.count()) ))

import functools


import operator as op
def op_use():
    asd=True
    print(op.truth(asd))
    list1=[1,2,3,1,2,1,4]
    print(op.countOf(list1,1))
    a=2
    if a in list1 :
        print(op.contains(list1,a))
    print(op.concat('asd',' is me.'),'asd'+' is me.')
    print(2&1,op.and_(2,1))
    print(pow(2,3),2**3)
    print(2 is 3,2 is not 3,op.is_(2,3),op.is_not(2,3))
    print(-2,op.neg(2),2<<1,op.lshift(2,1))
    # 矩阵乘法 ：matrix@matrix 
    
def str_format():
    '''str_format(1)
    '''
    str='my name is {} ,age {}'.format('hoho',18)
    li = ['hoho',18]
    str1='my name is {} ,age {}'.format(*li)
    str2='my name is {name},age is {age}'.format(name='hoho',age=19)
    print(str,'\n',str1,'\n',str2)
    print('{0:*>10}'.format(10),'{0:*<10}'.format(10),\
        '{0:*^10}'.format(10))
    print('{0:.2f}'.format(1/3),'{0:b}'.format(10),'{:,}'.format(12369132698))  
    print('name is {0[0]} age is {0[1]}'.format(['hoho', 18]))
    print("I'm %s. I'm %d year old" % ('Vamei', 99))
    print("I'm %(name)s. I'm %(age)d year old" % {'name':'Vamei', 'age':99})
    #flags可以有+,-,' '或0。+表示右对齐。-表示左对齐。' '为一个空格，表示在正数的左侧填充一个空格，从而与负数对齐。0表示使用0填充。
    print("%+10x" % 10) #16进制：x
    print("%04d" % 5)
    print("%06.3f" % 2.3)
    print("%.*f" % (3, 1.2)) #is %.4f 精度为4
#op_use()   
#str_format() 
def diedai():
    S = 'abcdefg'
    for (index,char) in enumerate(S):
        print(index,char)
    for i in range(0,len(S),2):
        print(S[i],end=' ')
#diedai()  

#函数对象的使用  
def test(f,a,b):
    print(f(a,b))
def fun(a,b):
    return a+b
#test(fun,3,4)
#test(lambda x,y:x+y,3,4)

#input('运行结束！')